jwt结合shiro实现认证和权限控制,非常详细 您所在的位置:网站首页 shiro 接口权限控制 jwt结合shiro实现认证和权限控制,非常详细

jwt结合shiro实现认证和权限控制,非常详细

#jwt结合shiro实现认证和权限控制,非常详细| 来源: 网络整理| 查看: 265

文章目录 前期准备 1. 导入依赖 2. 编写JwtUtil类 3. 封装token 4. 编写JWT的过滤器 5. 编写shiro的自定义Realm对象 6. 编写shiro配置文件 7. 捕获shiro异常 8. 编写controller 1.登录接口 2.用户接口 9. 测试结果 10. 常用注解接口 1. @RequiresAuthentication 2. @RequiresRoles 3. @RequiresPermissions 4. 结合运用

前期准备

jwt,我的理解就是可以进行客户端与服务端之间验证的一种技术,取代了之前使用Session来验证的不安全性。为什么不适用Session?

原理是,登录之后客户端和服务端各自保存一个相应的SessionId,每次客户端发起请求的时候就得携带这个SessionId来进行比对

Session在用户请求量大的时候服务器开销太大了 Session不利于搭建服务器的集群(也就是必须访问原本的那个服务器才能获取对应的SessionId) 小程序,APP不适用session,对于微信小程序,request请求每次都会先请求微信的服务器,再由微信的服务器去访问我们的后端服务器。这样子就不能识别出是哪台浏览器发送的请求。

1.首先,登录的话,不能在通过shiro自己的方法去验证了,因为我们自定义的token需要存储用户使用的token,所以登录的密码验证就不能通过shiro进行验证,而需要我们自己去验证密码的准确性,在登录方法里面可以,在realm认证方法里面也可以. 2.然后,基于token进行权限验证的话,我们请求所有需要认证的接口时候请求头里必须携带token,然后后端进行token认证,判断token是否合法是否过期等等… 3.token的刷新,可以自定义返回code,返回新的token,来进行token刷新工作. 4.token缓存在redis中,可以实现集群token的共享.可以使token的过期删除交给redis

在这里我先不涉及redis,单纯的jwt结合shiro,所以也没有做token的过期处理,登出处理,即使你使用shiro的logout方法登出,这里的token依然没有失效

由于使用jwt是无状态的,不需要使用session,所以需要把session关闭掉。具体的编码过程如下。

个人理解:

jwt负责生成token,取代shiro原生的UsernamePasswordToken;shiro负责认证和权限的校验 登录逻辑沿用jwt的登录逻辑,即登录时不需要调用shiro的subject.login()方法,只需要校验用户名和密码,然后返回token即可。到了需要进行权限认证时在执行login方法,这里使用的是jwtFilter来进行拦截。

这个工作的流程有,登录,权限控制:

登录,登录还是做简单的接受请求传递过来的参数,然后和数据库对比,是否一致,一致的话则通过登录,使用jwt生成token,不经过shiro的处理,因为被jwtFilter拦截了。 认证,认证的话先是被jwtFilter拦截,然后验证token,无异常就继续进入到shiro 如果是只要拥有登录权限的话,那么就经过认证方面就可以了 如果是要控制权限的话,那么就要先认证再授权

有兴趣看源码的话可以去我的项目地址clone下来:

项目地址:https://github.com/HTBWell/shiro-jwt.git

1. 导入依赖 org.apache.shiro shiro-spring 1.3.2 com.auth0 java-jwt 3.2.0 2. 编写JwtUtil类

JwtUtil类是用来生成token和验校验解码token的。

步骤:

设置密钥和token的有效时间 生成token 校验token 获取token的信息 import com.auth0.jwt.JWT; import com.auth0.jwt.JWTVerifier; import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.exceptions.JWTDecodeException; import com.auth0.jwt.interfaces.DecodedJWT; import com.example.demo.domain.User; import java.io.UnsupportedEncodingException; import java.util.Date; import java.util.HashMap; import java.util.Map; public class JWTUtil { //token有效时长 private static final long EXPIRE=30*60*1000L; //token的密钥 private static final String SECRET="jwt+shiro"; public static String createToken(User user) throws UnsupportedEncodingException { //token过期时间 Date date=new Date(System.currentTimeMillis()+EXPIRE); //jwt的header部分 Mapmap=new HashMap(); map.put("alg","HS256"); map.put("typ","JWT"); //使用jwt的api生成token String token= JWT.create() .withHeader(map) .withClaim("username", user.getUsername())//私有声明 .withExpiresAt(date)//过期时间 .withIssuedAt(new Date())//签发时间 .sign(Algorithm.HMAC256(SECRET));//签名 return token; } //校验token的有效性,1、token的header和payload是否没改过;2、没有过期 public static boolean verify(String token){ try { //解密 JWTVerifier verifier=JWT.require(Algorithm.HMAC256(SECRET)).build(); verifier.verify(token); return true; }catch (Exception e){ return false; } } //无需解密也可以获取token的信息 public static String getUsername(String token){ try { DecodedJWT jwt = JWT.decode(token); return jwt.getClaim("username").asString(); } catch (JWTDecodeException e) { return null; } } } 3. 封装token

封装token来替换Shiro原生Token,要实现AuthenticationToken接口

shiro默认supports的是UsernamePasswordToken,而我们现在采用了jwt的方式,所以这里我们自定义一个JwtToken,来完成shiro的supports方法。

import org.apache.shiro.authc.AuthenticationToken; public class JWTToken implements AuthenticationToken { private String token; public JWTToken(String token){ this.token=token; } @Override public Object getPrincipal() { return token; } @Override public Object getCredentials() { return token; } } 4. 编写JWT的过滤器

这个过滤器是我们的重点,这里我们继承的是Shiro内置的BasicHttpAuthenticationFilter,一个可以内置了可以自动登录方法的的过滤器。也可以继承AuthenticatingFilter。我这里两个都实现了,跑项目的时候只要一个就好了

这个过滤器是要注册到shiro配置里面去的,用来辅助shiro进行过滤处理。所有的请求都会到过滤器来进行处理。

我们需要重写几个方法:

isAccessAllowed:是否允许访问。如果带有 token,则对 token 进行检查,否则直接通过。如果请求头不存在 Token,则可能是执行登陆操作或者是游客状态访问,无需检查 token,直接返回 true isLoginAttempt:判断用户是否想要登入。检测 header 里面是否包含 Token 字段。 executeLogin:executeLogin实际上就是先调用createToken来获取token,这里我们重写了这个方法,就不会自动去调用createToken来获取token,然后调用getSubject方法来获取当前用户再调用login方法来实现登录,这也解释了我们为什么要自定义jwtToken,因为我们不再使用Shiro默认的UsernamePasswordToken了。 preHandle:拦截器的前置拦截,因为我们是前后端分析项目,项目中除了需要跨域全局配置之外,我们再拦截器中也需要提供跨域支持。这样,拦截器才不会在进入Controller之前就被限制了。 继承BasicHttpAuthenticationFilter import com.example.demo.shiro.JWTToken; import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.RequestMethod


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有